// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: wsfuyibing <682805@qq.com>
// Date: 2024-11-13

package common

import (
	"encoding/json"
	"gitee.com/go-libs/log/base"
	"gitee.com/go-libs/log/conf"
	"sync"
)

var entityPool = &sync.Pool{
	New: func() any {
		return &Entity{}
	},
}

// Entity
// 日志实体.
type Entity struct {
	Level     base.Level `json:"level"`
	Message   string     `json:"message"`
	Time      string     `json:"time"`
	TimeMicro int64      `json:"time_micro"`

	Stack string `json:"stack,omitempty"`

	TraceId            string `json:"trace_id,omitempty"`
	SpanId             string `json:"span_id,omitempty"`
	SpanPosition       int32  `json:"span_position,omitempty"`
	ParentSpanId       string `json:"parent_span_id,omitempty"`
	ParentSpanPosition int32  `json:"parent_span_position,omitempty"`

	Pid              int      `json:"pid,omitempty"`
	ServiceAddresses []string `json:"service_addresses,omitempty"`
	ServiceHost      string   `json:"service_host,omitempty"`
	ServicePort      int      `json:"service_port,omitempty"`
	ServiceName      string   `json:"service_name,omitempty"`
	ServiceVersion   string   `json:"service_version,omitempty"`
}

// NewEntity
// 取出实例.
func NewEntity(item Item) *Entity {
	return entityPool.Get().(*Entity).reset(item)
}

func NewEntityWithBody(body []byte) *Entity {
	o := entityPool.Get().(*Entity)
	o.unmarshal(body)
	return o
}

// Byte
// 转成 byte 列表.
func (o *Entity) Byte() []byte {
	if buf, err := json.Marshal(o); err == nil {
		return buf
	}
	return nil
}

// Release
// 释放实例.
func (o *Entity) Release() {
	o.unset()
	entityPool.Put(o)
}

// String
// 转成 string 文本.
func (o *Entity) String() string {
	if buf := o.Byte(); buf != nil {
		return string(buf)
	}
	return `{}`
}

// +---------------------------------------------------------------------------+
// | Access methods                                                            |
// +---------------------------------------------------------------------------+

func (o *Entity) reset(item Item) *Entity {
	cfg := conf.New()

	// 1. 基础信息.
	o.Level = item.Level()
	o.Message = item.Message()
	o.Time = item.Time().Format(cfg.TimeFormat.String())
	o.TimeMicro = item.Time().UnixMicro()

	// 2. 堆栈信息.
	if item.Level().IsFatal() && item.Stack() != nil {
		o.Stack = item.Stack().String()
	}

	// 3. 链路信息.
	if s, sp := item.Span(); s != nil {
		o.TraceId = item.TraceId().String()
		o.SpanId = s.String()
		o.SpanPosition = sp

		// 上级链路.
		if p, pp := item.ParentSpan(); p != nil {
			o.ParentSpanId = p.String()
			o.ParentSpanPosition = pp
		}
	}

	// 4. 服务信息.
	o.Pid = cfg.Pid
	o.ServiceAddresses = cfg.ServiceAddresses
	o.ServiceHost = cfg.ServiceHost
	o.ServiceName = cfg.ServiceName
	o.ServicePort = cfg.ServicePort
	o.ServiceVersion = cfg.ServiceVersion
	return o
}

func (o *Entity) unmarshal(buf []byte) {
	json.Unmarshal(buf, o)
}

func (o *Entity) unset() {
	o.Level, o.Message, o.Stack, o.TraceId = "", "", "", ""
	o.SpanId, o.ParentSpanId = "", ""
	o.SpanPosition, o.ParentSpanPosition = 0, 0
}
